/*----------------------------------------------------------------------------/
/  FatFs - Generic FAT Filesystem Module  R0.14                               /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2019, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/    this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/----------------------------------------------------------------------------*/

#include "ff.h" /* Declarations of FatFs API */

#if defined(CONFIG_GCC) || defined(TARGET_LINUX32) || defined(TARGET_LINUX64)

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>

FRESULT f_open (FIL *fp, const TCHAR* path, FF_BYTE mode)
{
	FILE *f = NULL;
	int pplus = 0;

	if (fp == NULL || path == NULL)
		return FR_INVALID_PARAMETER;

	if (mode & FA_OPEN_APPEND) {
		mode |= FA_OPEN_EXISTING;
	}

	if (mode & FA_OPEN_EXISTING) {
		if (access(path, 0) != 0)
			return FR_NO_FILE;
		pplus = 1;
	}

	if (mode & FA_CREATE_ALWAYS) {
		pplus = 0;
	}

	if (mode & (FA_WRITE|FA_CREATE_NEW|FA_CREATE_ALWAYS)) {
		if (pplus) {
			f = fopen(path, "wb+");
		}
		else  {
			f = fopen(path, "wb");
		}
		if (f == NULL)
			return FR_DENIED;
	}
	else if (mode & (FA_READ|FA_OPEN_APPEND|FA_OPEN_EXISTING)) {
		if (pplus) {
			f = fopen(path, "rb+");
		}
		else  {
			f = fopen(path, "rb");
		}
		if (f == NULL)
			return FR_NO_FILE;
	}
	else return FR_INVALID_PARAMETER;

	if (mode & FA_OPEN_APPEND) {
		fseek(f, 0L, SEEK_END);
	}

	*fp = (FIL)f;

	return FR_OK;
}

FRESULT f_close (FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return FR_INVALID_PARAMETER;

	f = *fp;

	if (fp == NULL)
		return FR_INVALID_PARAMETER;
	
	fclose(f);

	return FR_OK;
}

FRESULT f_read (FIL *fp, void* buff, FF_UINT btr, FF_UINT* br)
{
	FILE *f = NULL;
	size_t res;

	if (fp == NULL || buff == NULL || btr < 1 )
		return FR_INVALID_PARAMETER;

	f = *fp;
	if (f == NULL)
		return FR_INVALID_PARAMETER;

	res = fread(buff, 1, btr, f);

	if (br != NULL) {
		*br = res;
	}

	return FR_OK;
}

FRESULT f_write (FIL *fp, const void* buff, FF_UINT btw, FF_UINT* bw)
{
	FILE *f = NULL;
	size_t res;

	if (fp == NULL || buff == NULL || btw < 1)
		return FR_INVALID_PARAMETER;

	f = *fp;
	if (f == NULL)
		return FR_INVALID_PARAMETER;

	res = fwrite(buff, 1, btw, f);

	if (bw != NULL) {
		*bw = res;
	}

	return FR_OK;
}

FRESULT f_lseek (FIL *fp, FSIZE_t ofs)
{
	FILE *f = NULL;

	if (fp == NULL)
		return FR_INVALID_PARAMETER;

	f = *fp;
	if (f == NULL)
		return FR_INVALID_PARAMETER;

	fseek(f, ofs, SEEK_SET);

	return FR_OK;
}

FRESULT f_sync (FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return FR_INVALID_PARAMETER;

	f = *fp;
	if (f == NULL)
		return FR_INVALID_PARAMETER;

	fflush(f);

	return FR_OK;
}

int f_putc (TCHAR c, FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return -1;

	f = *fp;
	if (f == NULL)
		return -1;

	return fputc(c, f);
}

int f_puts (const TCHAR* str, FIL* fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return -1;

	f = *fp;
	if (f == NULL)
		return -1;

	return fputs(str, f);
}

int f_printf (FIL *fp, const TCHAR* str, ...)
{
	va_list args;
	int i;

	FILE *f = NULL;

	if (fp == NULL)
		return -1;

	f = *fp;
	if (f == NULL)
		return -1;

	va_start(args, str);

	i = vfprintf(f, str, args);

	va_end(args);

	return i;

}

TCHAR* f_gets (TCHAR* buff, int len, FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return NULL;

	f = *fp;
	if (f == NULL)
		return NULL;

	return fgets(buff, len, f);

}

int f_eof(FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return -1;

	f = *fp;
	if (f == NULL)
		return -1;

	return feof(f);
}

int f_error(FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return -1;

	f = *fp;
	if (f == NULL)
		return -1;

	return ferror(f);
}

long f_tell(FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return -1;
	f = *fp;
	if (f == NULL)
		return -1;

	return ftell(f);
}

void f_rewind(FIL *fp)
{
	FILE *f = NULL;

	if (fp == NULL)
		return;
	f = *fp;
	if (f == NULL)
		return;

	rewind(f);
}

long f_size(FIL *fp)
{
	long off, res;

	FILE *f = NULL;

	if (fp == NULL)
		return -1;
	f = *fp;
	if (f == NULL)
		return -1;

	off = ftell(f);
	fseek(f, 0L, SEEK_END);
	res = ftell(f);
	fseek(f, 0L, off);

	return res;
}

#endif
